package util;

import java.util.Collection;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

public class SharedStorageUtil implements IKeyValueStorage {
	/** Mutex objects for the storage operations. If an operation requires synchronization
	 *  of multiple mutexes at once, in order prevent deadlocks, synchronize them in the order they are
	 *  declared below **/
	private static Object mutexGet;
	private static Object mutexPut;
	private static Object mutexRemove;
	
	static {
		mutexGet = new Object();
		mutexPut = new Object();
		mutexRemove = new Object();
	}
	
	private static volatile ConcurrentHashMap<String, Object> sharedStorage;
	
	private static ConcurrentHashMap getSharedStorage() {
		if(sharedStorage==null) {
			sharedStorage = new ConcurrentHashMap<String, Object>();
		}
		return sharedStorage;
	}
	
	@Override
	public void put(String key, Object value) {
		synchronized(mutexGet) {
			synchronized(mutexPut) {
				getSharedStorage().put(key, value);
			}
		}
	}

	@Override
	public Object get(String key) {
		Object value = null;
		synchronized(mutexGet) {
			value = getSharedStorage().get(key);
		}
		return value;
	}

	@Override
	public boolean containsKey(String key) {
		boolean contains = false;
		synchronized (mutexPut) {
			contains = getSharedStorage().containsKey(key);
		}
		return contains;
	}

	@Override
	public boolean containsValue(String value) {
		boolean contains = false;
		synchronized (mutexPut) {
			contains = getSharedStorage().containsValue(value);
		}
		return contains;
	}

	@Override
	public synchronized Object remove(String key) {
		synchronized (mutexGet) {
			synchronized (mutexPut) {
				return getSharedStorage().remove(key);
			}
		}
	}

	@Override
	public int size() {
		synchronized (mutexPut) {
			return getSharedStorage().size();
		}
	}

	@Override
	public boolean isEmpty() {
		synchronized (mutexPut) {
			return getSharedStorage().isEmpty();
		}
	}

	@Override
	public void clear() {
		synchronized (mutexGet) {
			synchronized (mutexPut) {
				getSharedStorage().clear();
			}
		}
	}

	@Override
	public Set getKeysSet() {
		synchronized (mutexPut) {
			return getSharedStorage().keySet();
		}
	}
	
	@Override
	public synchronized Collection getValues() {
		synchronized (mutexPut) {
			return getSharedStorage().values();
		}
	}
}
